home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / c_news / 14 / paint.c < prev    next >
C/C++ Source or Header  |  1989-02-20  |  34KB  |  1,302 lines

  1. /* PAINT.C
  2.  *
  3.  * Scott R. Houck
  4.  * Written in Turbo C 2.0
  5.  *
  6.  * Add the EGAVGA.BGI driver to graphics.lib using the BGIOBJ program.
  7.  *
  8.  * Compile with:  tcc -ml paint graphics.lib
  9.  *
  10.  * This is a simple paint program
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <math.h>
  15. #include <dos.h>
  16. #include <mem.h>
  17. #include <alloc.h>
  18. #include <conio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <io.h>
  22. #include <ctype.h>
  23. #include <graphics.h>
  24.  
  25.  
  26. /* Mouse buttons */
  27.  
  28. #define LEFTBUTTON   1
  29. #define RIGHTBUTTON  2
  30.  
  31. /* Clipping */
  32.  
  33. #define CLIPPING_ON  1
  34. #define CLIPPING_OFF 0
  35.  
  36. /* Boolean values */
  37.  
  38. #define TRUE   1
  39. #define FALSE  0
  40.  
  41. /* Dialog box options */
  42.  
  43. #define YES    1
  44. #define NO     0
  45.  
  46. /* Menu choices */
  47.  
  48. #define IGNORE             -1
  49. #define PAINT              0
  50. #define FILL               1
  51. #define ERASER             2
  52. #define CLEAR              3
  53. #define SAVE               4
  54. #define LOAD               5
  55. #define QUIT               6
  56. #define RUBBER_LINE        7
  57. #define RUBBER_RECTANGLE   8
  58.  
  59.  
  60. #define LINE         0
  61. #define RECTANGLE    1
  62.  
  63. /* Some useful typedefs */
  64.  
  65. typedef struct pointtype   POINT;         /* A point with x and y as ints */
  66. typedef POINT              EXTENT [2];    /* Rectangular extent */
  67.  
  68.  
  69. /* Function prototypes */
  70.  
  71. void    InitializeGraphics(void);
  72. void    DrawScreen(void);
  73. int     MouseReset(int *);
  74. void    MouseOn(void);
  75. void    MouseOff(void);
  76. int     MouseStatus(POINT *);
  77. void    MouseWaitForPress(int, POINT *);
  78. void    MouseWaitForRelease(int, POINT *);
  79. void    MouseSetCursor(int [16][2]);
  80. void    HighlightMenu(int, int, int);
  81. int     PointInExtent(POINT, EXTENT);
  82. void    HandleDraw(POINT);
  83. int     PickCorrInMenu(POINT);
  84. int     PickCorrInColor(POINT);
  85. int     PickCorrInPattern(POINT);
  86. void    HandlePick(POINT);
  87. void    SetForeground(int);
  88. void    SetBackground(int);
  89. void    SetPattern(int);
  90. void    DoPaint(POINT);
  91. void    DoFill(POINT);
  92. void    DoEraser(POINT);
  93. void    DoClear(void);
  94. void    DoSave(void);
  95. void    DoLoad(void);
  96. void    DoRubber(int, POINT);
  97. int     DialogBox(void);
  98. void    Beep(void);
  99. void    LowBeep(void);
  100. int     GetChar(char *, char *, int *);
  101. char *  GetString(char *, int, int, int, char *, char *, char *, int,
  102.             int (*)(int, int));
  103. int     PromptForFilename(char *);
  104.  
  105.  
  106. /* Global variables */
  107.  
  108. int maxx, maxy;                        /* Maximum pixel values */
  109. int dminx, dminy, dmaxx, dmaxy;        /* Drawing area coordinates */
  110. int bgminx, bgminy, bgmaxx, bgmaxy;    /* Background box */
  111. int fgminx, fgminy, fgmaxx, fgmaxy;    /* Foreground box */
  112. int rl1x, rl1y, rl2x, rl2y;            /* Rubber line coordinates */
  113. int rr1x, rr1y, rr2x, rr2y;            /* Rubber rectangle coordinates */
  114. int xminx, xminy, xmaxx, xmaxy;        /* Dialog box coordinates */
  115. EXTENT drawExtent;                     /* Extent of the drawing area */
  116. EXTENT colorExtent[16];                /* Extents of the 16 color boxes */
  117. EXTENT patternExtent[11];              /* Extents of the 11 patterns */
  118. EXTENT yesExtent, noExtent;            /* Extent of the YES/NO buttons */
  119. int currentColor;                      /* Current foreground color */
  120. int fillPattern;                       /* Current fill pattern */
  121. int fillColor;                         /* Current fill color */
  122. unsigned dialogSize;                   /* Dialog box image size */
  123. unsigned drawSize;                     /* Drawing size */
  124. unsigned promptSize;                   /* Size of prompt box */
  125. void *dialogBuffer, *saveBuffer;       /* Dialog box and screen buffers */
  126. void *promptBuffer, *drawBuffer;       /* Prompt box and drawing buffers */
  127. int fminx, fminy, fmaxx, fmaxy;        /* File prompt box coords */
  128. int promptx, prompty;                  /* File prompt x and y coords */
  129.  
  130. struct {
  131.    EXTENT extent;
  132.    char *text;
  133. } menuBox[10];       /* menu buttons */
  134.  
  135. int mode;            /* current mode */
  136.  
  137.  
  138. /* The following two arrays define the eraser-type cursor and the
  139.  * regular arrow cursor for use in the MouseSetCursor() routine.
  140.  */
  141.  
  142. int eraser [16][2] = {
  143.    { 0xFFFF, 0xFFFF },  /* screen mask */
  144.    { 0xFFFF, 0xFFFF },
  145.    { 0xFFFF, 0xFFFF },
  146.    { 0xFFFF, 0xFFFF },
  147.    { 0xFFFF, 0xFFFF },
  148.    { 0xFFFF, 0xFFFF },
  149.    { 0xFFFF, 0xFFFF },
  150.    { 0xFFFF, 0xFFFF },
  151.  
  152.    { 0xFFFF, 0x8001 },  /* cursor mask */
  153.    { 0x8001, 0x8001 },
  154.    { 0x8001, 0x8001 },
  155.    { 0x8001, 0xFFFF },
  156.    { 0x0000, 0x0000 },
  157.    { 0x0000, 0x0000 },
  158.    { 0x0000, 0x0000 },
  159.    { 0x0000, 0x0000 }
  160. };
  161.  
  162. int cursor [16][2] = {
  163.    { 0x3FFF, 0x1FFF },  /* screen mask */
  164.    { 0x0FFF, 0x07FF },
  165.    { 0x03FF, 0x01FF },
  166.    { 0x00FF, 0x007F },
  167.    { 0x003F, 0x001F },
  168.    { 0x01FF, 0x10FF },
  169.    { 0x30FF, 0xF87F },
  170.    { 0xF87F, 0xFC7F },
  171.  
  172.    { 0x0000, 0x4000 },  /* cursor mask */
  173.    { 0x6000, 0x7000 },
  174.    { 0x7800, 0x7C00 },
  175.    { 0x7E00, 0x7F00 },
  176.    { 0x7F80, 0x7C00 },
  177.    { 0x6C00, 0x4600 },
  178.    { 0x0600, 0x0300 },
  179.    { 0x0300, 0x0000 }
  180. };
  181.  
  182.  
  183.  
  184. main()
  185. {
  186.    POINT position;
  187.    int buttonPressed;
  188.  
  189.    InitializeGraphics();
  190.    DrawScreen();
  191.    MouseOn();
  192.  
  193.    HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
  194.  
  195.    while (mode != QUIT)
  196.       {
  197.       do
  198.          {
  199.          buttonPressed = MouseStatus(&position);
  200.          if (mode == ERASER && PointInExtent(position, drawExtent))
  201.             MouseSetCursor(eraser);
  202.          else
  203.             MouseSetCursor(cursor);
  204.          }
  205.       while (!(buttonPressed & (RIGHTBUTTON | LEFTBUTTON)));
  206.  
  207.       if (PointInExtent(position, drawExtent))
  208.          HandleDraw(position);
  209.       else
  210.          HandlePick(position);
  211.       }
  212.  
  213.    MouseOff();
  214.    closegraph();
  215. }
  216.  
  217.  
  218. /* InitializeGraphics() initializes the graphics package and mouse driver.
  219.  * If there is an error, the program aborts with an appropriate error
  220.  * message.
  221.  */
  222. void InitializeGraphics()
  223. {
  224.    int graphDriver, graphMode, errorCode;
  225.    int numberOfButtons;
  226.  
  227.    if (MouseReset(&numberOfButtons) == 0)
  228.       {
  229.       printf("Mouse driver is not installed\n");
  230.       exit(1);
  231.       }
  232.  
  233.    if (numberOfButtons < 2)
  234.       {
  235.       printf("This program requires a mouse with at least two buttons\n");
  236.       exit(2);
  237.       }
  238.  
  239.    if (registerbgidriver(EGAVGA_driver) < 0)
  240.       exit(1);
  241.  
  242.    graphDriver = DETECT;
  243.    initgraph(&graphDriver, &graphMode, "");
  244.    errorCode = graphresult();
  245.    if (errorCode != grOk)
  246.       {
  247.       printf("Graphics System Error: %s\n", grapherrormsg(errorCode));
  248.       exit(1);
  249.       }
  250.  
  251.    /* Get maximum x and y screen coordinates */
  252.  
  253.    maxx = getmaxx();
  254.    maxy = getmaxy();
  255. }
  256.  
  257.  
  258. void DrawScreen()
  259. {
  260.    int i;
  261.    int cminx, cminy, cmaxx, cmaxy;  /* color box coordinates */
  262.    int pminx, pminy, pmaxx, pmaxy;  /* pattern box coordinates */
  263.    int cwidth;                      /* width of color box */
  264.    int cheight;                     /* height of color box */
  265.    int pwidth;                      /* width of pattern box */
  266.    int gap;                         /* gap between various objects */
  267.    int bminx, bminy, bmaxx, bmaxy;        /* Menu buttons */
  268.    int bwidth, bheight, bgap, bstart;     /* Menu buttons */
  269.    int dwidth, dheight;                   /* Drawing area dimensions */
  270.    int xwidth, xheight;                   /* Dialog box dimensions */
  271.    int yminx, yminy, ymaxx, ymaxy;        /* YES button */
  272.    int nminx, nminy, nmaxx, nmaxy;        /* NO button */
  273.    int fwidth, fheight;                   /* Height of file prompt box */
  274.    static char *boxText[] = { "PAINT", "FILL", "ERASER", "CLEAR", "SAVE",
  275.       "LOAD", "QUIT", "", "" };
  276.  
  277.    setvisualpage(0);
  278.    setactivepage(0);
  279.  
  280.    /* Draw the main background */
  281.  
  282.    setcolor(WHITE);
  283.    rectangle(0, 0, maxx, maxy);
  284.    setfillstyle(INTERLEAVE_FILL, CYAN);
  285.    floodfill(1, 1, WHITE);
  286.  
  287.    /* Draw the drawing area */
  288.  
  289.    drawExtent[0].x = dminx = (int)(0.30 * maxx);
  290.    drawExtent[0].y = dminy = (int)(0.05 * maxy);
  291.    drawExtent[1].x = dmaxx = (int)(0.95 * maxx);
  292.    drawExtent[1].y = dmaxy = (int)(0.80 * maxy);
  293.  
  294.    drawSize = imagesize(dminx, dminy, dmaxx, dmaxy);
  295.    drawBuffer = malloc(drawSize);
  296.  
  297.    dwidth  = dmaxx - dminx;
  298.    dheight = dmaxy - dminy;
  299.  
  300.    setfillstyle(SOLID_FILL, WHITE);
  301.    setcolor(WHITE);
  302.    rectangle(dminx-1, dminy-1, dmaxx+1, dmaxy+1);
  303.    floodfill(dminx, dminy, WHITE);
  304.  
  305.    /* Draw the dialog box */
  306.  
  307.    setactivepage(1);
  308.  
  309.    xwidth  = (int)(0.35 * dwidth);
  310.    xheight = (int)(0.25 * dheight);
  311.    xminx   = dminx + (dwidth - xwidth) / 2;
  312.    xminy   = dminy + (dheight - xheight) / 2;
  313.    xmaxx   = xminx + xwidth;
  314.    xmaxy   = xminy + xheight;
  315.    rectangle(xminx, xminy, xmaxx, xmaxy);    /* The outline */
  316.  
  317.    yesExtent[0].x = yminx = xminx + (int)(0.10 * xwidth);
  318.    yesExtent[0].y = yminy = xminy + (int)(0.60 * xheight);
  319.    yesExtent[1].x = ymaxx = xminx + (int)(0.40 * xwidth);
  320.    yesExtent[1].y = ymaxy = xminy + (int)(0.90 * xheight);
  321.    rectangle(yminx, yminy, ymaxx, ymaxy);
  322.    setfillstyle(SOLID_FILL, BLUE);
  323.    floodfill(yminx+1, yminy+1, WHITE);  /* YES button */
  324.  
  325.    noExtent[0].x = nminx = xminx + (int)(0.60 * xwidth);
  326.    noExtent[0].y = nminy = yminy;
  327.    noExtent[1].x = nmaxx = xminx + (int)(0.90 * xwidth);
  328.    noExtent[1].y = nmaxy = ymaxy;
  329.    rectangle(nminx, nminy, nmaxx, nmaxy);
  330.    floodfill(nminx+1, nminy+1, WHITE);  /* NO button */
  331.  
  332.    setfillstyle(SOLID_FILL, LIGHTGRAY);
  333.    floodfill(xminx+1, xminy+1, WHITE);  /* The interior */
  334.  
  335.    settextjustify(CENTER_TEXT, CENTER_TEXT);
  336.    moveto(xminx+xwidth/2, xminy+(yminy-xminy)/2);
  337.    setcolor(BLACK);
  338.    outtext("Are you sure?");
  339.    setcolor(WHITE);
  340.    moveto((yminx+ymaxx)/2, (yminy+ymaxy)/2);
  341.    outtext("YES");
  342.    moveto((nminx+nmaxx)/2, (nminy+nmaxy)/2);
  343.    outtext("NO");
  344.    setcolor(WHITE);
  345.  
  346.    /* Save dialog box in memory */
  347.  
  348.    dialogSize = imagesize(xminx, xminy, xmaxx, xmaxy);
  349.    dialogBuffer = malloc(dialogSize);
  350.    getimage(xminx, xminy, xmaxx, xmaxy, dialogBuffer);
  351.  
  352.    /* Draw the prompt box */
  353.  
  354.    cleardevice();
  355.    fwidth  = (int)(0.35 * dwidth);
  356.    fheight = (int)(0.20 * dheight);
  357.    fminx   = dminx + (int)(0.25 * dwidth);
  358.    fminy   = dminy + (dheight - fheight) / 2;
  359.    fmaxx   = fminx + fwidth;
  360.    fmaxy   = fminy + fheight;
  361.    rectangle(fminx, fminy, fmaxx, fmaxy); /* The outline */
  362.  
  363.    promptx = fminx + (int)(0.40 * fwidth);
  364.    prompty = (fminy + fmaxy) / 2;
  365.    rectangle(promptx-5, prompty-fheight/6, fminx + (int)(0.90 * fwidth),
  366.       prompty+fheight/6);  /* Draw the filename input box */
  367.  
  368.    setfillstyle(SOLID_FILL, CYAN);
  369.    floodfill(fminx+1, fminy+1, WHITE);
  370.    moveto(fminx+8, prompty);
  371.    setcolor(BLACK);
  372.    settextjustify(LEFT_TEXT, CENTER_TEXT);
  373.    outtext("File:");
  374.    setcolor(WHITE);
  375.  
  376.    setfillstyle(SOLID_FILL, WHITE);
  377.    floodfill(promptx+1, prompty, WHITE);
  378.  
  379.    /* Save the prompt box in memory */
  380.  
  381.    promptSize = imagesize(fminx, fminy, fmaxx, fmaxy);
  382.    promptBuffer = malloc(promptSize);
  383.    getimage(fminx, fminy, fmaxx, fmaxy, promptBuffer);
  384.  
  385.    setactivepage(0);
  386.  
  387.    /* Draw the color boxes */
  388.  
  389.    cwidth  = (int)((dmaxx - dminx) / 16.0);
  390.    cheight = (int)(0.07 * maxy);
  391.    gap     = (int)(0.025 * maxy);
  392.  
  393.    cminy = dmaxy + gap;
  394.    cmaxy = cminy + cheight;
  395.  
  396.    for (i = 0; i < 16; i++)
  397.       {
  398.       colorExtent[i][0].x = cminx = dminx + i * cwidth;
  399.       colorExtent[i][0].y = cminy;
  400.       colorExtent[i][1].x = cmaxx = cminx + cwidth;
  401.       colorExtent[i][1].y = cmaxy;
  402.       rectangle(cminx, cminy, cmaxx, cmaxy);
  403.       setfillstyle(SOLID_FILL, i);
  404.       floodfill(cminx+3, cminy+3, WHITE);
  405.       }
  406.  
  407.    /* Draw the pattern boxes */
  408.  
  409.    pwidth = (int)((dmaxx - dminx) / 11.0);
  410.    pminy  = cmaxy + gap;
  411.    pmaxy  = pminy + cheight;
  412.  
  413.    for (i = 0; i < 11; i++)
  414.       {
  415.       patternExtent[i][0].x = pminx = dminx + i * pwidth;
  416.       patternExtent[i][0].y = pminy;
  417.       patternExtent[i][1].x = pmaxx = pminx + pwidth;
  418.       patternExtent[i][1].y = pmaxy;
  419.       rectangle(pminx, pminy, pmaxx, pmaxy);
  420.       setfillstyle(i+1, WHITE);
  421.       floodfill(pminx+3, pminy+3, WHITE);
  422.       }
  423.  
  424.    /* Draw the menu buttons */
  425.  
  426.    bheight = (int)(0.055 * maxy);
  427.    bwidth  = (int)(0.150 * maxx);
  428.    bgap    = (int)(0.025 * maxy);
  429.    bstart  = (int)(0.050 * maxy);
  430.    setfillstyle(SOLID_FILL, BLUE);
  431.    bminx = (int)(0.05 * maxx);
  432.    for (i = 0; i < 9; i++)
  433.       {
  434.       bminy = (int)(i * (bheight + bgap)) + bstart;
  435.       bmaxx = bminx + bwidth;
  436.       bmaxy = bminy + bheight;
  437.       rectangle(bminx, bminy, bmaxx, bmaxy);
  438.       floodfill(bminx+1, bminy+1, WHITE);
  439.       moveto(bminx+bwidth/2, bminy+bheight/2);
  440.       settextjustify(CENTER_TEXT, CENTER_TEXT);
  441.       outtext(boxText[i]);
  442.  
  443.       /* Initialize the menuBox info */
  444.  
  445.       menuBox[i].extent[0].x = bminx;
  446.       menuBox[i].extent[0].y = bminy;
  447.       menuBox[i].extent[1].x = bmaxx;
  448.       menuBox[i].extent[1].y = bmaxy;
  449.       menuBox[i].text = boxText[i];
  450.  
  451.       if (i == RUBBER_LINE)
  452.          {
  453.          rl1x = bminx + (int)(0.20 * (bmaxx-bminx));
  454.          rl1y = bmaxy - (int)(0.20 * (bmaxy-bminy));
  455.          rl2x = bmaxx - (int)(0.20 * (bmaxx-bminx));
  456.          rl2y = bminy + (int)(0.20 * (bmaxy-bminy));
  457.          line(rl1x, rl1y, rl2x, rl2y);
  458.          }
  459.  
  460.       if (i == RUBBER_RECTANGLE)
  461.          {
  462.          rr1x = bminx + (int)(0.20 * (bmaxx-bminx));
  463.          rr1y = bminy + (int)(0.20 * (bmaxy-bminy));
  464.          rr2x = bmaxx - (int)(0.20 * (bmaxx-bminx));
  465.          rr2y = bmaxy - (int)(0.20 * (bmaxy-bminy));
  466.          rectangle(rr1x, rr1y, rr2x, rr2y);
  467.          }
  468.       }
  469.  
  470.    /* Draw the foreground/background box */
  471.  
  472.    bgminx = (int)(0.15 * maxx);
  473.    bgminy = (int)(0.83 * maxy);
  474.    bgmaxx = (int)(0.25 * maxx);
  475.    bgmaxy = (int)(0.97 * maxy);
  476.    rectangle(bgminx, bgminy, bgmaxx, bgmaxy);
  477.    
  478.    fgminx = bgminx + (int)(0.20 * (bgmaxx-bgminx));
  479.    fgminy = bgminy + (int)(0.20 * (bgmaxy-bgminy));
  480.    fgmaxx = bgmaxx - (int)(0.20 * (bgmaxx-bgminx));
  481.    fgmaxy = bgmaxy - (int)(0.20 * (bgmaxy-bgminy));
  482.    rectangle(fgminx, fgminy, fgmaxx, fgmaxy);
  483.  
  484.    setfillstyle(SOLID_FILL, WHITE);
  485.    floodfill(bgminx+3, bgminy+3, WHITE);
  486.  
  487.    setfillstyle(SOLID_FILL, BLACK);
  488.    floodfill(fgminx+3, fgminy+3, WHITE);
  489.  
  490.    /* Set defaults */
  491.  
  492.    currentColor = BLACK;
  493.    fillPattern  = SOLID_FILL;
  494.    fillColor    = WHITE;
  495.    setcolor(currentColor);
  496.    setfillstyle(fillPattern, fillColor);
  497.    setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
  498. }
  499.  
  500.  
  501. /* MouseReset() returns the current status of the mouse hardware and
  502.  * software.  The mouse status is 0 if the mouse hardware and software
  503.  * are not installed or -1 if the hardware and software are installed.
  504.  *
  505.  * This function also resets the mouse driver to the default values.
  506.  * The number of buttons is returned in numberOfButtons.
  507.  */
  508. int MouseReset(int *numberOfButtons)
  509. {
  510.    union REGS inregs, outregs;
  511.  
  512.    inregs.x.ax = 0;  /* Mouse Function 0 -- Mouse Reset and Status */
  513.    int86(0x33, &inregs, &outregs);
  514.    *numberOfButtons = outregs.x.bx;
  515.    return outregs.x.ax;
  516. }
  517.  
  518.  
  519. /* MouseOn() shows the mouse cursor. */
  520.  
  521. void MouseOn()
  522. {
  523.    union REGS inregs, outregs;
  524.  
  525.    inregs.x.ax = 1;  /* Mouse Function 1 -- Show Cursor */
  526.    int86(0x33, &inregs, &outregs);
  527. }
  528.  
  529.  
  530. /* MouseOff() hides the mouse cursor. */
  531.  
  532. void MouseOff()
  533. {
  534.    union REGS inregs, outregs;
  535.  
  536.    inregs.x.ax = 2;  /* Mouse function 2 -- Hide Cursor */
  537.    int86(0x33, &inregs, &outregs);
  538. }
  539.  
  540.  
  541. /* MouseStatus() returns the state of the left and right mouse buttons
  542.  * and the horizontal and vertical coordinates of the cursor.
  543.  *
  544.  * The button status is a single integer value.  Bit 0 represents the
  545.  * left button; bit 1 represents the right button.  These bits are 1
  546.  * if the corresponding button is down, and 0 if it is up.
  547.  */
  548. int MouseStatus(POINT *position)
  549. {
  550.    union REGS inregs, outregs;
  551.  
  552.    inregs.x.ax = 3;  /* Mouse function 3 --
  553.                         Get Button Status and Mouse Position */
  554.    int86(0x33, &inregs, &outregs);
  555.    position->x = outregs.x.cx;
  556.    position->y = outregs.x.dx;
  557.    return outregs.x.bx; /* Button status */
  558. }
  559.  
  560.  
  561. /* MouseWaitForPress() puts the program in a wait state until the
  562.  * user presses the specified mouse button.
  563.  */
  564. void MouseWaitForPress(int button, POINT *posptr)
  565. {
  566.    int buttonPressed;
  567.  
  568.    do
  569.       buttonPressed = MouseStatus(posptr);
  570.    while (!(buttonPressed & button));
  571. }
  572.  
  573.  
  574. /* MouseWaitForRelease() puts the program in a wait state until the
  575.  * user releases the specified mouse button.
  576.  */
  577. void MouseWaitForRelease(int button, POINT *posptr)
  578. {
  579.    int buttonPressed;
  580.  
  581.    do
  582.       buttonPressed = MouseStatus(posptr);
  583.    while (buttonPressed & button);
  584. }
  585.  
  586.  
  587. void MouseSetCursor(int picture[16][2])
  588. {
  589.    struct SREGS segregs;
  590.    union REGS inregs, outregs;
  591.  
  592.    segread(&segregs);
  593.    inregs.x.ax = 9;  /* Mouse function 9 -- Set Graphics Cursor */
  594.    inregs.x.bx = 0;
  595.    inregs.x.cx = 0;
  596.    inregs.x.dx = (int) picture;
  597.    segregs.es = segregs.ds;
  598.    int86x(0x33, &inregs, &outregs, &segregs);
  599. }
  600.  
  601.  
  602. /* HighlightMenu() highlights the specified menu box. */
  603.  
  604. void HighlightMenu(int box, int background, int foreground)
  605. {
  606.    struct viewporttype view;
  607.    struct fillsettingstype fill;
  608.    int color;
  609.    int bminx = menuBox[box].extent[0].x;
  610.    int bminy = menuBox[box].extent[0].y;
  611.    int bmaxx = menuBox[box].extent[1].x;
  612.    int bmaxy = menuBox[box].extent[1].y;
  613.  
  614.    MouseOff();
  615.  
  616.    /* Get attributes */
  617.  
  618.    getviewsettings(&view);
  619.    getfillsettings(&fill);
  620.    color = getcolor();
  621.  
  622.    setviewport(bminx, bminy, bmaxx, bmaxy, CLIPPING_OFF);
  623.    clearviewport();
  624.  
  625.    setviewport(0, 0, maxx, maxy, CLIPPING_OFF);
  626.    setcolor(WHITE);
  627.    rectangle(bminx, bminy, bmaxx, bmaxy);
  628.  
  629.    setfillstyle(SOLID_FILL, background);
  630.    floodfill(bminx+1, bminy+1, WHITE);
  631.  
  632.    settextjustify(CENTER_TEXT, CENTER_TEXT);
  633.    setcolor(foreground);
  634.    moveto((bminx + bmaxx) / 2, (bminy + bmaxy) / 2);
  635.    outtext(menuBox[box].text);
  636.  
  637.    if (box == RUBBER_LINE)
  638.       line(rl1x, rl1y, rl2x, rl2y);
  639.  
  640.    if (box == RUBBER_RECTANGLE)
  641.       rectangle(rr1x, rr1y, rr2x, rr2y);
  642.  
  643.    /* Reset attributes */
  644.  
  645.    setviewport(view.left, view.top, view.right, view.bottom, view.clip);
  646.    setfillstyle(fill.pattern, fill.color);
  647.    setcolor(color);
  648.  
  649.    MouseOn();
  650. }
  651.  
  652.  
  653. /* PointInExtent() returns a boolean value specifying whether a point
  654.  * is in a certain extent.
  655.  */
  656. int PointInExtent(POINT pt, EXTENT ext)
  657. {
  658.    return ext[0].x <= pt.x && pt.x <= ext[1].x &&
  659.           ext[0].y <= pt.y && pt.y <= ext[1].y;
  660. }
  661.  
  662.  
  663. /* HandleDraw() dispatches to the correct routine depending on the
  664.  * current mode while the user has the mouse cursor in the drawing
  665.  * area.
  666.  */
  667. void HandleDraw(POINT position)
  668. {
  669.    int numberOfButtons;
  670.  
  671.    switch (mode)
  672.       {
  673.       case PAINT:
  674.          DoPaint(position);
  675.          break;
  676.  
  677.       case FILL:
  678.          DoFill(position);
  679.          break;
  680.  
  681.       case ERASER:
  682.          DoEraser(position);
  683.          break;
  684.  
  685.       case RUBBER_LINE:
  686.          DoRubber(LINE, position);
  687.          break;
  688.  
  689.       case RUBBER_RECTANGLE:
  690.          DoRubber(RECTANGLE, position);
  691.          break;
  692.       }
  693. }
  694.  
  695.  
  696. /* PickCorrInMenu() performs pick correlation within the menu box area. */
  697.  
  698. int PickCorrInMenu(POINT pt)
  699. {
  700.    int i;
  701.  
  702.    for (i = 0; i < 9; i++)
  703.       if (PointInExtent(pt, menuBox[i].extent))
  704.          return i;
  705.  
  706.    return IGNORE;
  707. }
  708.  
  709.  
  710. /* PickCorrInColor() performs pick correlation within the foreground and
  711.  * background color boxes.
  712.  */
  713. int PickCorrInColor(POINT pt)
  714. {
  715.    int i;
  716.  
  717.    for (i = 0; i < 16; i++)
  718.       if (PointInExtent(pt, colorExtent[i]))
  719.          return i;
  720.  
  721.    return IGNORE;
  722. }
  723.  
  724.  
  725. /* PickCorrInPattern() performs pick correlation within the pattern
  726.  * boxes.
  727.  */
  728. int PickCorrInPattern(POINT pt)
  729. {
  730.    int i;
  731.  
  732.    for (i = 0; i < 11; i++)
  733.       if (PointInExtent(pt, patternExtent[i]))
  734.          return i;
  735.  
  736.    return IGNORE;
  737. }
  738.  
  739.  
  740. /* HandlePick() sets the current mode of the program and handles other
  741.  * cases when the mouse cursor is outside of the drawing area.
  742.  */
  743. void HandlePick(POINT position)
  744. {
  745.    int choice;
  746.  
  747.    if ((choice = PickCorrInMenu(position)) != IGNORE)
  748.       switch (choice)
  749.          {
  750.          case PAINT:
  751.             HighlightMenu(mode, BLUE, WHITE);
  752.             HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
  753.             break;
  754.  
  755.          case FILL:
  756.             HighlightMenu(mode, BLUE, WHITE);
  757.             HighlightMenu(mode = FILL, LIGHTGRAY, BLACK);
  758.             break;
  759.  
  760.          case ERASER:
  761.             HighlightMenu(mode, BLUE, WHITE);
  762.             HighlightMenu(mode = ERASER, LIGHTGRAY, BLACK);
  763.             break;
  764.  
  765.          case CLEAR:
  766.             HighlightMenu(mode, BLUE, WHITE);
  767.             HighlightMenu(CLEAR, LIGHTGRAY, BLACK);
  768.             DoClear();
  769.             HighlightMenu(CLEAR, BLUE, WHITE);
  770.             HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
  771.             break;
  772.  
  773.          case SAVE:
  774.             HighlightMenu(mode, BLUE, WHITE);
  775.             HighlightMenu(SAVE, LIGHTGRAY, BLACK);
  776.             DoSave();
  777.             HighlightMenu(SAVE, BLUE, WHITE);
  778.             HighlightMenu(mode, LIGHTGRAY, BLACK);
  779.             break;
  780.  
  781.          case LOAD:
  782.             HighlightMenu(mode, BLUE, WHITE);
  783.             HighlightMenu(LOAD, LIGHTGRAY, BLACK);
  784.             DoLoad();
  785.             HighlightMenu(LOAD, BLUE, WHITE);
  786.             HighlightMenu(mode, LIGHTGRAY, BLACK);
  787.             break;
  788.  
  789.          case QUIT:
  790.             if (DialogBox() == YES)
  791.                mode = QUIT;
  792.             break;
  793.  
  794.          case RUBBER_LINE:
  795.             HighlightMenu(mode, BLUE, WHITE);
  796.             HighlightMenu(mode = RUBBER_LINE, LIGHTGRAY, BLACK);
  797.             break;
  798.  
  799.          case RUBBER_RECTANGLE:
  800.             HighlightMenu(mode, BLUE, WHITE);
  801.             HighlightMenu(mode = RUBBER_RECTANGLE, LIGHTGRAY, BLACK);
  802.             break;
  803.          }
  804.  
  805.    else if ((choice = PickCorrInColor(position)) != IGNORE)
  806.       {
  807.       if (MouseStatus(&position) & LEFTBUTTON)
  808.          SetForeground(choice);
  809.       else
  810.          SetBackground(choice);
  811.       }
  812.  
  813.    else if ((choice = PickCorrInPattern(position)) != IGNORE)
  814.       SetPattern(choice);
  815. }
  816.  
  817.  
  818. /* SetForeground() sets the current color (foreground) which is used
  819.  * when drawing.
  820.  */
  821. void SetForeground(int color)
  822. {
  823.    MouseOff();
  824.    currentColor = color;
  825.    setcolor(currentColor);
  826.    setviewport(fgminx+1, fgminy+1, fgmaxx-1, fgmaxy-1, CLIPPING_ON);
  827.    clearviewport();
  828.    setfillstyle(SOLID_FILL, color);
  829.    floodfill(3, 3, WHITE);
  830.    setfillstyle(fillPattern, fillColor);
  831.    setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
  832.    MouseOn();
  833. }
  834.  
  835.  
  836. /* SetBackground() sets the current fill color, which is also the color
  837.  * used when the drawing area is cleared by selecting the CLEAR option
  838.  * from the menu buttons.
  839.  */
  840. void SetBackground(int color)
  841. {
  842.    MouseOff();
  843.    fillColor = color;
  844.    setviewport(bgminx+1, bgminy+1, bgmaxx-1, bgmaxy-1, CLIPPING_ON);
  845.    clearviewport();
  846.    setfillstyle(fillPattern, fillColor);
  847.    floodfill(3, 3, WHITE);
  848.    MouseOn();
  849.    SetForeground(currentColor);
  850. }
  851.  
  852.  
  853. /* SetPattern() sets the current fill pattern, which is also the pattern
  854.  * used when the drawing area is cleared by selecting the CLEAR option
  855.  * from the menu buttons.
  856.  */
  857. void SetPattern(int pattern)
  858. {
  859.    MouseOff();
  860.    fillPattern = pattern + 1;
  861.    setfillstyle(fillPattern, fillColor);
  862.    MouseOn();
  863.    SetBackground(fillColor);
  864. }
  865.  
  866.  
  867. /* DoPaint() handles the paint option. */
  868.  
  869. void DoPaint(POINT position)
  870. {
  871.    int first = TRUE;
  872.    POINT oldpt = position;
  873.  
  874.    moveto(position.x-dminx, position.y-dminy);
  875.  
  876.    while (MouseStatus(&position) & LEFTBUTTON)
  877.       if (first || position.x != oldpt.x || position.y != oldpt.y)
  878.          {
  879.          first = FALSE;
  880.          MouseOff();
  881.          lineto(position.x-dminx, position.y-dminy);
  882.          oldpt = position;
  883.          MouseOn();
  884.          }
  885. }
  886.  
  887.  
  888. /* DoFill() handles the fill option.  The floodfill() function requires
  889.  * that the border color be specified, so DoFill() compares pixels in
  890.  * increasing x coordinates until a different color is found, and then
  891.  * uses that color as the border color argument to floodfill().
  892.  */
  893. void DoFill(POINT position)
  894. {
  895.    int interior, border;
  896.    int x = position.x-dminx;
  897.  
  898.    MouseWaitForRelease(LEFTBUTTON, &position);
  899.  
  900.    MouseOff();
  901.  
  902.    interior = getpixel(position.x-dminx, position.y-dminy);
  903.    do
  904.       border = getpixel(++x, position.y-dminy);
  905.    while (border == interior);
  906.  
  907.    floodfill(position.x-dminx, position.y-dminy, border);
  908.  
  909.    MouseOn();
  910. }
  911.  
  912.  
  913. /* DoEraser handles the ERASER option.  It uses a rectangular cursor as
  914.  * an eraser, drawing lines in the background color.  If the cursor is
  915.  * moved outside the drawing area, the eraser reverts to the normal cursor
  916.  * shape.
  917.  */
  918. void DoEraser(POINT position)
  919. {
  920.    int i, x, y, first = TRUE;
  921.    POINT oldpt = position;
  922.  
  923.    setcolor(fillColor);
  924.  
  925.    while (MouseStatus(&position) & LEFTBUTTON)
  926.       {
  927.       if (PointInExtent(position, drawExtent))
  928.          MouseSetCursor(eraser);
  929.       else
  930.          MouseSetCursor(cursor);
  931.       if (first || position.x != oldpt.x || position.y != oldpt.y)
  932.          {
  933.          first = FALSE;
  934.          MouseOff();
  935.          x = position.x - dminx;
  936.          y = position.y - dminy;
  937.          for (i = 0; i < 8; i++)
  938.             line(x, y+i, x+15, y+i);
  939.          oldpt = position;
  940.          MouseOn();
  941.          }
  942.       }
  943.  
  944.    setcolor(currentColor);
  945. }
  946.  
  947.  
  948. /* DoClear() clears the drawing area in the current background color and
  949.  * pattern after receiving confirmation from the user by means of a dialog
  950.  * box.
  951.  */
  952. void DoClear()
  953. {
  954.    if (DialogBox() == YES)
  955.       {
  956.       MouseOff();
  957.       clearviewport();
  958.       floodfill(5, 5, WHITE);
  959.       MouseOn();
  960.       }
  961. }
  962.  
  963.  
  964. /* DoSave() saves the drawing */
  965.  
  966. void DoSave()
  967. {
  968.    FILE *outfile;
  969.    char filename[13];
  970.  
  971.    PromptForFile(filename);
  972.  
  973.    if ((outfile = fopen(filename, "wb")) == NULL)
  974.       return;
  975.    setviewport(0, 0, maxx, maxy, CLIPPING_ON);
  976.  
  977.    MouseOff();
  978.    getimage(dminx, dminy, dmaxx, dmaxy, drawBuffer);
  979.    MouseOn();
  980.  
  981.    setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
  982.    fwrite(drawBuffer, drawSize, 1, outfile);
  983.    fclose(outfile);
  984. }
  985.  
  986.  
  987. /* DoLoad() loads a file into the drawing area. */
  988.  
  989. void DoLoad()
  990. {
  991.    FILE *infile;
  992.    char filename[13];
  993.    int status;
  994.    
  995.    status = PromptForFile(filename);
  996.    if (status != 0)  /* File does not exist */
  997.       {
  998.       LowBeep();
  999.       return;
  1000.       }
  1001.  
  1002.    if ((infile = fopen(filename, "rb")) == NULL)
  1003.       return;
  1004.    fread(drawBuffer, drawSize, 1, infile);
  1005.    fclose(infile);
  1006.    setviewport(0, 0, maxx, maxy, CLIPPING_ON);
  1007.  
  1008.    MouseOff();
  1009.    putimage(dminx, dminy, drawBuffer, COPY_PUT);
  1010.    MouseOn();
  1011.  
  1012.    setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
  1013. }
  1014.  
  1015.  
  1016. /* DoRubber() performs a rubber line/rectangle drawing routine. */
  1017.  
  1018. void DoRubber(int type, POINT position)
  1019. {
  1020.    POINT anchor = position;
  1021.    POINT oldpt  = position;
  1022.  
  1023.    setwritemode(XOR_PUT);
  1024.    setcolor(currentColor ^ 15);
  1025.    moveto(anchor.x-dminx, anchor.y-dminy);
  1026.  
  1027.    while (MouseStatus(&position) & LEFTBUTTON)
  1028.       {
  1029.       if (position.x != oldpt.x || position.y != oldpt.y)
  1030.          {
  1031.          MouseOff();
  1032.          /* erase old and draw new */
  1033.          if (type == LINE)
  1034.             {
  1035.             line(anchor.x-dminx, anchor.y-dminy, oldpt.x-dminx,
  1036.                oldpt.y-dminy);
  1037.             line(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
  1038.                position.y-dminy);
  1039.             }
  1040.          else
  1041.             {
  1042.             rectangle(anchor.x-dminx, anchor.y-dminy, oldpt.x-dminx,
  1043.                oldpt.y-dminy);
  1044.             rectangle(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
  1045.                position.y-dminy);
  1046.             }
  1047.          oldpt = position;
  1048.          MouseOn();
  1049.          }
  1050.       }
  1051.  
  1052.    setcolor(currentColor);
  1053.    setwritemode(COPY_PUT);
  1054.  
  1055.    /* draw final */
  1056.    MouseOff();
  1057.    if (type == LINE)
  1058.       line(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
  1059.          position.y-dminy);
  1060.    else
  1061.       rectangle(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
  1062.          position.y-dminy);
  1063.    MouseOn();
  1064. }
  1065.  
  1066.  
  1067. /* DialogBox() pops up a dialog box containing the message "Are you sure?"
  1068.  * It returns YES or NO depending on the user's choice.
  1069.  */
  1070. int DialogBox()
  1071. {
  1072.    POINT position;
  1073.    int choice, done = FALSE;
  1074.    struct viewporttype view;
  1075.  
  1076.    MouseOff();
  1077.  
  1078.    getviewsettings(&view);
  1079.    setviewport(0, 0, maxx, maxy, CLIPPING_OFF);   /* Entire screen */
  1080.  
  1081.    /* Save the screen area under where the dialog box will display */
  1082.    saveBuffer = malloc(dialogSize);
  1083.    getimage(xminx, xminy, xmaxx, xmaxy, saveBuffer);
  1084.  
  1085.    /* Display the dialog box */
  1086.    putimage(xminx, xminy, dialogBuffer, COPY_PUT);
  1087.  
  1088.    MouseOn();
  1089.  
  1090.    do
  1091.       {
  1092.       MouseWaitForPress(LEFTBUTTON, &position);
  1093.       MouseWaitForRelease(LEFTBUTTON, &position);
  1094.       if (PointInExtent(position, yesExtent))
  1095.          {
  1096.          choice = YES;
  1097.          done = TRUE;
  1098.          }
  1099.       else if (PointInExtent(position, noExtent))
  1100.          {
  1101.          choice = NO;
  1102.          done = TRUE;
  1103.          }
  1104.       }
  1105.    while (!done);
  1106.  
  1107.    /* Restore the screen area and free the buffer */
  1108.  
  1109.    MouseOff();
  1110.    putimage(xminx, xminy, saveBuffer, COPY_PUT);
  1111.    free(saveBuffer);
  1112.    MouseOn();
  1113.  
  1114.    setviewport(view.left, view.top, view.right, view.bottom, view.clip);
  1115.    return choice;
  1116. }
  1117.  
  1118.  
  1119. void Beep()
  1120. {
  1121.    sound(1000);
  1122.    delay(150);
  1123.    nosound();
  1124. }
  1125.  
  1126.  
  1127. void LowBeep()
  1128. {
  1129.    sound(100);
  1130.    delay(150);
  1131.    nosound();
  1132. }
  1133.  
  1134.  
  1135. /* GetChar() gets a character from the keyboard.  legalchars and
  1136.  * legalscans are strings that contain the characters and scan codes
  1137.  * that the function will accept.
  1138.  */
  1139. int GetChar(char *legalchars, char *legalscans, int *scancode)
  1140. {
  1141.    int ch, ok;
  1142.  
  1143.    do
  1144.       {
  1145.       ch = getch();
  1146.       if ((ch == '\0') && kbhit())     /* extended key */
  1147.          ok = (strchr(legalscans, *scancode = getch()) != NULL);
  1148.       else
  1149.          ok = (strchr(legalchars, ch) != NULL);
  1150.       if (!ok)
  1151.          Beep();
  1152.       }
  1153.    while (!ok);
  1154.  
  1155.    return ch;
  1156. }
  1157.  
  1158.  
  1159. /* GetString() gets a string of input */
  1160.  
  1161. char *GetString(char *inpstr, int x, int y, int width, char *deflt,
  1162.    char *legalchars, char *legalscans, int upcaseFlag,
  1163.    int (*keyHandler)(int, int))
  1164. {
  1165.    char ch, temp[2], blanks[80];
  1166.    int len, scancode, done = FALSE;
  1167.  
  1168.    /* blanks is a string of character 219's -- block characters */
  1169.    memset(blanks, 219, width);
  1170.    blanks[width] = '\0';
  1171.  
  1172.    settextjustify(LEFT_TEXT, CENTER_TEXT);
  1173.  
  1174.    inpstr[0] = '\0'; /* Initialize the string to empty */
  1175.  
  1176.    /* Write the default */
  1177.    moveto(x, y);
  1178.    outtext(deflt);
  1179.  
  1180.    do
  1181.       {
  1182.       len = strlen(inpstr);
  1183.       ch = GetChar(legalchars, legalscans, &scancode);
  1184.       if (upcaseFlag)
  1185.          ch = toupper(ch);
  1186.       switch (ch)
  1187.          {
  1188.          case '\b':  /* Backspace */
  1189.             if (len == 0)
  1190.                Beep();
  1191.             else
  1192.                {
  1193.                inpstr[len-1] = '\0';   /* Truncate the string */
  1194.                /* Blank out the input area and write the input string */
  1195.                setcolor(WHITE);
  1196.                moveto(x, y);
  1197.                outtext(blanks);
  1198.                setcolor(BLACK);
  1199.                moveto(x, y);
  1200.                if (strlen(inpstr) == 0)
  1201.                   outtext(deflt);
  1202.                else
  1203.                   outtext(inpstr);
  1204.                }
  1205.             break;
  1206.  
  1207.          case '\x1b':   /* Escape key */
  1208.             /* Blank out the input area and write the default */
  1209.             setcolor(WHITE);
  1210.             moveto(x, y);
  1211.             outtext(blanks);
  1212.             setcolor(BLACK);
  1213.             inpstr[0] = '\0';
  1214.             moveto(x, y);
  1215.             outtext(deflt);
  1216.             break;
  1217.  
  1218.          case '\r':
  1219.             done = TRUE;
  1220.             break;
  1221.  
  1222.          case '\0':  /* Handle function keys if desired */
  1223.             done = (*keyHandler)(ch, scancode);
  1224.             break;
  1225.  
  1226.          default:
  1227.             if (len < width)
  1228.                {
  1229.                if (len == 0)
  1230.                   {
  1231.                   setcolor(WHITE);
  1232.                   moveto(x, y);
  1233.                   outtext(blanks);
  1234.                   setcolor(BLACK);
  1235.                   moveto(x, y);
  1236.                   }
  1237.                temp[0] = ch;
  1238.                temp[1] = '\0';
  1239.                strcat(inpstr, temp);   /* accept the character */
  1240.                outtext(temp);
  1241.                }
  1242.             else
  1243.                Beep();     /* len was equal to width */
  1244.          }
  1245.       }
  1246.    while (!done);
  1247.  
  1248.    if (len == 0)
  1249.       strcpy(inpstr, deflt);
  1250.  
  1251.    return inpstr;
  1252. }
  1253.  
  1254.  
  1255.  
  1256. /* PromptForFile prompts the user for a filename.  It returns 0 if the
  1257.  * file exists, 1 if it does not exist.
  1258.  */
  1259. int PromptForFile(char *filename)
  1260. {
  1261.    struct viewporttype view;
  1262.    int ch, scancode;
  1263.  
  1264.    /* Don't allow backslashes, periods, colons, etc. */
  1265.    char *legalchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
  1266.                       "abcdefghijklmnopqrstuvwxyz" \
  1267.                       "01234567890!@#$%^&()-_=`~[]{}'\"" \
  1268.                       "\b\x1b\r";
  1269.  
  1270.    MouseOff();
  1271.  
  1272.    getviewsettings(&view);
  1273.    setviewport(0, 0, maxx, maxy, CLIPPING_OFF);   /* Entire screen */
  1274.  
  1275.    /* Save the screen area under where the prompt box will display */
  1276.    saveBuffer = malloc(promptSize);
  1277.    getimage(fminx, fminy, fmaxx, fmaxy, saveBuffer);
  1278.  
  1279.    /* Display the prompt box */
  1280.    putimage(fminx, fminy, promptBuffer, COPY_PUT);
  1281.  
  1282.    MouseOn();
  1283.  
  1284.    /* Get the filename from the user */
  1285.    GetString(filename, promptx, prompty, 8, "PAINT", legalchars,
  1286.       NULL, TRUE, NULL);
  1287.  
  1288.    strcat(filename, ".pic");
  1289.  
  1290.    /* Restore the screen area and free the buffer */
  1291.  
  1292.    MouseOff();
  1293.    putimage(fminx, fminy, saveBuffer, COPY_PUT);
  1294.    MouseOn();
  1295.  
  1296.    free(saveBuffer);
  1297.  
  1298.    setviewport(view.left, view.top, view.right, view.bottom, view.clip);
  1299.    return access(filename, 0);
  1300. }
  1301.  
  1302.